package nsfs

import (
	"GLibHac/crypto"
	"encoding/hex"
	"fmt"
	"github.com/magiconair/properties"
	"os"
)

type KeySet struct {
	ExternalKeySet                map[string]*crypto.AccessKey
	SecureBootKey                 *crypto.AesKey
	TsecKey                       *crypto.AesKey
	Package1MacKek                *crypto.AesKey
	TsecRootKek                   *crypto.AesKey
	DeviceKey                     *crypto.AesKey
	Package1Kek                   *crypto.AesKey
	TsecAuthSignatures            []*crypto.AesKey
	ETicketExtKeyRsa              *crypto.RSAParameters
	TsecRootKeys                  []*crypto.AesKey
	KeyBlobMacKeySource           *crypto.AesKey
	KeyBlobKeySources             []*crypto.AesKey
	KeyBlobKeys                   []*crypto.AesKey
	KeyBlobMacKeys                []*crypto.AesKey
	MasterKekSources              []*crypto.AesKey
	MarikoBek                     *crypto.AesKey
	MarikoKek                     *crypto.AesKey
	MarikoMasterKekSources        []*crypto.AesKey
	MarikoAesClassKeys            []*crypto.AesKey
	MasterKeks                    []*crypto.AesKey
	MasterKeySource               *crypto.AesKey
	Package1MacKeys               []*crypto.AesKey
	Package1Keys                  []*crypto.AesKey
	MasterKeys                    []*crypto.AesKey
	Package2KeySource             *crypto.AesKey
	Package2Keys                  []*crypto.AesKey
	BisKekSource                  *crypto.AesKey
	BisKeySources                 []*crypto.AesXtsKey
	BisKeys                       []*crypto.AesXtsKey
	KeyAreaKeys                   [][]*crypto.AesKey
	ETicketRsaKek                 *crypto.AesKey
	PerConsoleKeySource           *crypto.AesKey
	RetailSpecificAesKeySource    *crypto.AesKey
	AesKekGenerationSource        *crypto.AesKey
	AesKeyGenerationSource        *crypto.AesKey
	TitleKekSource                *crypto.AesKey
	HeaderKekSource               *crypto.AesKey
	HeaderKeySource               *crypto.AesXtsKey
	HeaderKey                     *crypto.AesXtsKey
	KeyAreaKeyApplicationSource   *crypto.AesKey
	KeyAreaKeyOceanSource         *crypto.AesKey
	KeyAreaKeySystemSource        *crypto.AesKey
	DeviceUniqueSaveMacKekSource  *crypto.AesKey
	SeedUniqueSaveMacKekSource    *crypto.AesKey
	SeedUniqueSaveMacKeySource    *crypto.AesKey
	SeedUniqueSaveMacKey          *crypto.AesKey
	SdCardEncryptionSeed          *crypto.AesKey
	SdCardKekSource               *crypto.AesKey
	XciHeaderKey                  *crypto.AesKey
	SslRsaKek                     *crypto.AesKey
	GcTitleKeyKeks                []*crypto.AesKey
	TitleKeks                     []*crypto.AesKey
	DeviceUniqueSaveMacKeySources []*crypto.AesKey
	DeviceUniqueSaveMacKeys       []*crypto.AesKey
	SdCardKeySources              []*crypto.AesXtsKey
	EncryptedKeyBlobs             []*crypto.EncryptedKeyBlob
	KeyBlobs                      []*crypto.KeyBlob
}

func (k *KeySet) ImportTickets(fileSystem IFileSystem) error {
	return fileSystem.EnumerateEntries("/", ".*\\.tik", func(ticketEntry *DirectoryEntryEx) error {
		ticketFile, err := fileSystem.OpenFile(ticketEntry.Path, OpenFileModeRead)
		if err != nil {
			return err
		}
		ticket, err := NewTicket(ticketFile.AsStorage())
		if err != nil {
			return err
		}
		if ticket.Type == TitleKeyTypeCommon {
			key, err := ticket.GetTitleKey(k)
			if err != nil {
				return err
			}
			k.ExternalKeySet[string(ticket.RightsId)] = crypto.NewAccessKey(key)
		}
		return nil
	})
}

func createAesKeyArray(size int) []*crypto.AesKey {
	aesKeys := make([]*crypto.AesKey, size)
	for i := 0; i < size; i++ {
		aesKeys[i] = crypto.NewDefaultAesKey()
	}
	return aesKeys
}
func createAesXtsKeyArray(size int) []*crypto.AesXtsKey {
	aesKeys := make([]*crypto.AesXtsKey, size)
	for i := 0; i < size; i++ {
		aesKeys[i] = crypto.NewAesXtsKey()
	}
	return aesKeys
}

func createKeyAreaKeys() [][]*crypto.AesKey {
	keys := make([][]*crypto.AesKey, 32)
	for i := 0; i < 32; i++ {
		keys[i] = createAesKeyArray(3)
	}
	return keys
}

func createEncryptedKeyBlobArray() []*crypto.EncryptedKeyBlob {
	keys := make([]*crypto.EncryptedKeyBlob, 32)
	for i := 0; i < 32; i++ {
		keys[i] = crypto.NewEncryptedKeyBlob()
	}
	return keys
}

func createKeyBlobArray() []*crypto.KeyBlob {
	keys := make([]*crypto.KeyBlob, 32)
	for i := 0; i < 32; i++ {
		keys[i] = crypto.NewKeyBlob()
	}
	return keys
}

func NewDefaultKeySet() *KeySet {
	keySet := &KeySet{
		ExternalKeySet:                make(map[string]*crypto.AccessKey),
		SecureBootKey:                 crypto.NewDefaultAesKey(),
		TsecKey:                       crypto.NewDefaultAesKey(),
		Package1MacKek:                crypto.NewDefaultAesKey(),
		TsecRootKek:                   crypto.NewDefaultAesKey(),
		DeviceKey:                     crypto.NewDefaultAesKey(),
		Package1Kek:                   crypto.NewDefaultAesKey(),
		TsecAuthSignatures:            createAesKeyArray(32),
		ETicketExtKeyRsa:              crypto.NewRSAParameters(),
		TsecRootKeys:                  createAesKeyArray(32),
		KeyBlobMacKeySource:           crypto.NewDefaultAesKey(),
		KeyBlobKeySources:             createAesKeyArray(32),
		KeyBlobKeys:                   createAesKeyArray(32),
		KeyBlobMacKeys:                createAesKeyArray(32),
		MasterKekSources:              createAesKeyArray(32),
		MarikoBek:                     crypto.NewDefaultAesKey(),
		MarikoKek:                     crypto.NewDefaultAesKey(),
		MarikoAesClassKeys:            createAesKeyArray(12),
		MarikoMasterKekSources:        createAesKeyArray(32),
		MasterKeks:                    createAesKeyArray(32),
		MasterKeySource:               crypto.NewDefaultAesKey(),
		Package1MacKeys:               createAesKeyArray(32),
		Package1Keys:                  createAesKeyArray(32),
		MasterKeys:                    createAesKeyArray(32),
		Package2KeySource:             crypto.NewDefaultAesKey(),
		Package2Keys:                  createAesKeyArray(32),
		BisKekSource:                  crypto.NewDefaultAesKey(),
		BisKeySources:                 createAesXtsKeyArray(4),
		BisKeys:                       createAesXtsKeyArray(4),
		KeyAreaKeys:                   createKeyAreaKeys(),
		ETicketRsaKek:                 crypto.NewDefaultAesKey(),
		PerConsoleKeySource:           crypto.NewDefaultAesKey(),
		RetailSpecificAesKeySource:    crypto.NewDefaultAesKey(),
		AesKekGenerationSource:        crypto.NewDefaultAesKey(),
		AesKeyGenerationSource:        crypto.NewDefaultAesKey(),
		TitleKekSource:                crypto.NewDefaultAesKey(),
		HeaderKekSource:               crypto.NewDefaultAesKey(),
		HeaderKeySource:               crypto.NewAesXtsKey(),
		HeaderKey:                     crypto.NewAesXtsKey(),
		KeyAreaKeyApplicationSource:   crypto.NewDefaultAesKey(),
		KeyAreaKeyOceanSource:         crypto.NewDefaultAesKey(),
		KeyAreaKeySystemSource:        crypto.NewDefaultAesKey(),
		DeviceUniqueSaveMacKekSource:  crypto.NewDefaultAesKey(),
		SeedUniqueSaveMacKekSource:    crypto.NewDefaultAesKey(),
		SeedUniqueSaveMacKeySource:    crypto.NewDefaultAesKey(),
		SeedUniqueSaveMacKey:          crypto.NewDefaultAesKey(),
		SdCardEncryptionSeed:          crypto.NewDefaultAesKey(),
		SdCardKekSource:               crypto.NewDefaultAesKey(),
		XciHeaderKey:                  crypto.NewDefaultAesKey(),
		SslRsaKek:                     crypto.NewDefaultAesKey(),
		GcTitleKeyKeks:                make([]*crypto.AesKey, 16),
		TitleKeks:                     createAesKeyArray(32),
		DeviceUniqueSaveMacKeySources: createAesKeyArray(2),
		DeviceUniqueSaveMacKeys:       createAesKeyArray(2),
		SdCardKeySources:              createAesXtsKeyArray(3),
		EncryptedKeyBlobs:             createEncryptedKeyBlobArray(),
		KeyBlobs:                      createKeyBlobArray(),
	}
	return keySet
}

type KeyRangeType uint8

func (k KeyRangeType) String() string {
	switch k {
	case KeyRangeTypeSingle:
		return "Single"
	case KeyRangeTypeRange:
		return "Range"
	default:
		return fmt.Sprintf("KeyRangeType(%d)", k)
	}
}

const (
	KeyRangeTypeSingle = KeyRangeType(iota)
	KeyRangeTypeRange  = KeyRangeType(iota)
)

type KeyType int

func (k KeyType) String() string {
	switch k {
	case KeyTypeCommon:
		return "Common"
	case KeyTypeDevice:
		return "Device"
	case KeyTypeRoot:
		return "Root"
	case KeyTypeSeed:
		return "Seed"
	case KeyTypeDerived:
		return "Derived"
	case KeyTypeDifferentDev:
		return "DifferentDev"
	case KeyTypeCommonRoot:
		return "CommonRoot"
	case KeyTypeCommonSeed:
		return "CommonSeed"
	case KeyTypeCommonSeedDiff:
		return "CommonSeedDiff"
	case KeyTypeCommonDrvd:
		return "CommonDrvd"
	case KeyTypeDeviceRoot:
		return "DeviceRoot"
	case KeyTypeDeviceDrvd:
		return "DeviceDrvd"
	default:
		return fmt.Sprintf("KeyType(%d)", k)
	}
}

const (
	KeyTypeCommon         = KeyType(1)
	KeyTypeDevice         = KeyType(1 << 1)
	KeyTypeRoot           = KeyType(1 << 2)
	KeyTypeSeed           = KeyType(1 << 3)
	KeyTypeDerived        = KeyType(1 << 4)
	KeyTypeDifferentDev   = KeyType(1 << 5)
	KeyTypeCommonRoot     = KeyType(KeyTypeCommon | KeyTypeRoot)
	KeyTypeCommonSeed     = KeyType(KeyTypeCommon | KeyTypeSeed)
	KeyTypeCommonSeedDiff = KeyType(KeyTypeCommon | KeyTypeSeed | KeyTypeDifferentDev)
	KeyTypeCommonDrvd     = KeyType(KeyTypeCommon | KeyTypeDerived)
	KeyTypeDeviceRoot     = KeyType(KeyTypeDevice | KeyTypeRoot)
	KeyTypeDeviceDrvd     = KeyType(KeyTypeDevice | KeyTypeDerived)
)

type KeyGetter func(keySet *KeySet, i int) *crypto.AesKey

type KeyInfo struct {
	Name       string
	Getter     KeyGetter
	RangeType  KeyRangeType
	Type       KeyType
	Group      int
	RangeStart int
	RangeEnd   int
}

func (info *KeyInfo) Matches(keyName string) (int, error) {
	if info.RangeType == KeyRangeTypeSingle {
		if info.Name == keyName {
			return 1, nil
		}
	} else {
		i := len(keyName) - 3
		if keyName[i] == '_' {
			s := keyName[i+1:]
			if keyName == info.Name+"_"+s {
				data, err := hex.DecodeString(s)
				if err != nil {
					return 0, err
				}
				return int(data[0]), nil
			}
		}
	}
	return -1, nil
}

func CreateKeyList() []*KeyInfo {
	// Keys with a group value of -1 are keys that will be read but not written.
	// This is for compatibility since some keys had other names in the past.

	// TSEC secrets aren't public yet, so the TSEC root keys will be treated as
	// root keys even though they're derived.
	return []*KeyInfo{
		NewKeyInfoSingle(10, KeyTypeDeviceRoot, "secure_boot_key", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.SecureBootKey }),
		NewKeyInfoSingle(11, KeyTypeDeviceRoot, "tsec_key", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.TsecKey }),
		NewKeyInfoSingle(12, KeyTypeDeviceDrvd, "device_key", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.DeviceKey }),
		NewKeyInfoSingle(20, KeyTypeCommonRoot, "tsec_root_kek", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.TsecRootKek }),
		NewKeyInfoSingle(21, KeyTypeCommonRoot, "package1_mac_kek", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.Package1MacKek }),
		NewKeyInfoSingle(22, KeyTypeCommonRoot, "package1_kek", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.Package1Kek }),
		NewKeyInfoRange(30, KeyTypeCommonRoot, "tsec_auth_signature", 0, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.TsecAuthSignatures[i] }),
		NewKeyInfoRange(40, KeyTypeCommonRoot, "tsec_root_key", 0, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.TsecRootKeys[i] }),
		NewKeyInfoSingle(50, KeyTypeCommonSeed, "keyblob_mac_key_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.KeyBlobMacKeySource }),
		NewKeyInfoRange(51, KeyTypeCommonSeed, "keyblob_key_source", 0, 6, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.KeyBlobKeySources[i] }),
		NewKeyInfoRange(55, KeyTypeDeviceDrvd, "keyblob_key", 0, 6, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.KeyBlobKeys[i] }),
		NewKeyInfoRange(60, KeyTypeDeviceDrvd, "keyblob_mac_key", 0, 6, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.KeyBlobMacKeys[i] }),
		NewKeyInfoRange(70, KeyTypeDeviceRoot, "encrypted_keyblob", 0, 6, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.EncryptedKeyBlobs[i].AesKey }),
		NewKeyInfoRange(80, KeyTypeCommonRoot, "keyblob", 0, 6, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.KeyBlobs[i].AesKey }),
		NewKeyInfoRange(90, KeyTypeCommonSeed, "master_kek_source", 6, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.MasterKekSources[i] }),
		NewKeyInfoSingle(100, KeyTypeCommonRoot, "mariko_bek", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.MarikoBek }),
		NewKeyInfoSingle(101, KeyTypeCommonRoot, "mariko_kek", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.MarikoKek }),
		NewKeyInfoRange(110, KeyTypeCommonRoot, "mariko_aes_class_key", 0, 0xC, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.MarikoAesClassKeys[i] }),
		NewKeyInfoRange(120, KeyTypeCommonSeedDiff, "mariko_master_kek_source", 0, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.MarikoMasterKekSources[i] }),
		NewKeyInfoRange(130, KeyTypeCommonDrvd, "master_kek", 0, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.MasterKeks[i] }),
		NewKeyInfoSingle(140, KeyTypeCommonSeed, "master_key_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.MasterKeySource }),
		NewKeyInfoRange(150, KeyTypeCommonDrvd, "master_key", 0, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.MasterKeys[i] }),
		NewKeyInfoRange(160, KeyTypeCommonDrvd, "package1_key", 0, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.Package1Keys[i] }),
		NewKeyInfoRange(170, KeyTypeCommonDrvd, "package1_mac_key", 6, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.Package1MacKeys[i] }),
		NewKeyInfoSingle(180, KeyTypeCommonSeed, "package2_key_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.Package2KeySource }),
		NewKeyInfoRange(190, KeyTypeCommonDrvd, "package2_key", 0, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.Package2Keys[i] }),
		NewKeyInfoSingle(200, KeyTypeCommonSeed, "bis_kek_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.BisKekSource }),
		NewKeyInfoRange(201, KeyTypeCommonSeed, "bis_key_source", 0, 4, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.BisKeySources[i].AesKey }),
		NewKeyInfoRange(205, KeyTypeDeviceDrvd, "bis_key", 0, 4, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.BisKeys[i].AesKey }),
		NewKeyInfoSingle(210, KeyTypeCommonSeed, "per_console_key_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.PerConsoleKeySource }),
		NewKeyInfoSingle(211, KeyTypeCommonSeed, "retail_specific_aes_key_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.RetailSpecificAesKeySource }),
		NewKeyInfoSingle(212, KeyTypeCommonSeed, "aes_kek_generation_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.AesKekGenerationSource }),
		NewKeyInfoSingle(213, KeyTypeCommonSeed, "aes_key_generation_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.AesKeyGenerationSource }),
		NewKeyInfoSingle(214, KeyTypeCommonSeed, "titlekek_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.TitleKekSource }),
		NewKeyInfoRange(220, KeyTypeCommonDrvd, "titlekek", 0, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.TitleKeks[i] }),
		NewKeyInfoSingle(230, KeyTypeCommonSeed, "header_kek_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.HeaderKekSource }),
		NewKeyInfoSingle(231, KeyTypeCommonSeed, "header_key_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.HeaderKeySource.AesKey }),
		NewKeyInfoSingle(232, KeyTypeCommonDrvd, "header_key", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.HeaderKey.AesKey }),
		NewKeyInfoSingle(240, KeyTypeCommonSeed, "key_area_key_application_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.KeyAreaKeyApplicationSource }),
		NewKeyInfoSingle(241, KeyTypeCommonSeed, "key_area_key_ocean_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.KeyAreaKeyOceanSource }),
		NewKeyInfoSingle(242, KeyTypeCommonSeed, "key_area_key_system_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.KeyAreaKeySystemSource }),
		NewKeyInfoSingle(250, KeyTypeCommonSeed, "save_mac_kek_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.DeviceUniqueSaveMacKekSource }),
		NewKeyInfoRange(251, KeyTypeCommonSeed, "save_mac_key_source", 0, 2, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.DeviceUniqueSaveMacKeySources[i] }),
		NewKeyInfoRange(252, KeyTypeDeviceDrvd, "save_mac_key", 0, 2, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.DeviceUniqueSaveMacKeys[i] }),
		NewKeyInfoSingle(-1, KeyTypeCommonSeed, "save_mac_key_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.DeviceUniqueSaveMacKeySources[0] }),
		NewKeyInfoSingle(253, KeyTypeCommonSeed, "save_mac_sd_card_kek_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.SeedUniqueSaveMacKekSource }),
		NewKeyInfoSingle(254, KeyTypeCommonSeed, "save_mac_sd_card_key_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.SeedUniqueSaveMacKeySource }),
		NewKeyInfoSingle(255, KeyTypeDeviceDrvd, "save_mac_sd_card_key", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.SeedUniqueSaveMacKey }),
		NewKeyInfoSingle(260, KeyTypeDeviceRoot, "sd_seed", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.SdCardEncryptionSeed }),
		NewKeyInfoSingle(261, KeyTypeCommonSeed, "sd_card_kek_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.SdCardKekSource }),
		NewKeyInfoSingle(262, KeyTypeCommonSeed, "sd_card_save_key_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.SdCardKeySources[0].AesKey }),
		NewKeyInfoSingle(263, KeyTypeCommonSeed, "sd_card_nca_key_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.SdCardKeySources[1].AesKey }),
		NewKeyInfoSingle(264, KeyTypeCommonSeed, "sd_card_custom_storage_key_source", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.SdCardKeySources[2].AesKey }),
		NewKeyInfoSingle(270, KeyTypeCommonSeedDiff, "xci_header_key", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.XciHeaderKey }),
		NewKeyInfoRange(271, KeyTypeCommonRoot, "xci_t1_titlekey_kek", 0, 0x10, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.GcTitleKeyKeks[i] }),
		NewKeyInfoSingle(280, KeyTypeCommonRoot, "eticket_rsa_kek", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.ETicketRsaKek }),
		NewKeyInfoSingle(281, KeyTypeCommonRoot, "ssl_rsa_kek", func(keySet *KeySet, i int) *crypto.AesKey { return keySet.SslRsaKek }),
		NewKeyInfoRange(290, KeyTypeCommonDrvd, "key_area_key_application", 0, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.KeyAreaKeys[i][0] }),
		NewKeyInfoRange(300, KeyTypeCommonDrvd, "key_area_key_ocean", 0, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.KeyAreaKeys[i][1] }),
		NewKeyInfoRange(310, KeyTypeCommonDrvd, "key_area_key_system", 0, 0x20, func(keySet *KeySet, i int) *crypto.AesKey { return keySet.KeyAreaKeys[i][2] }),
	}
}

func NewKeyInfoSingle(group int, Type KeyType, name string, retrieveFunc KeyGetter) *KeyInfo {
	return &KeyInfo{
		Name:       name,
		RangeType:  KeyRangeTypeSingle,
		Type:       Type,
		RangeStart: 0,
		RangeEnd:   0,
		Group:      group,
		Getter:     retrieveFunc,
	}
}

func NewKeyInfoRange(group int, Type KeyType, name string, rangeStart, rangeEnd int, retrieveFunc KeyGetter) *KeyInfo {
	return &KeyInfo{
		Name:       name,
		RangeType:  KeyRangeTypeRange,
		Type:       Type,
		RangeStart: rangeStart,
		RangeEnd:   rangeEnd,
		Group:      group,
		Getter:     retrieveFunc,
	}
}

func ReloadKeySetFromFile(keySet *KeySet, keyFile string) error {
	keyList := CreateKeyList()
	keyContent, err := os.ReadFile(keyFile)
	if err != nil {
		return err
	}
	return ReadMainKeys(keySet, string(keyContent), keyList)
}

type SpecificKeyInfo struct {
	Info  *KeyInfo
	Index int
}

func typeGetKeyInfo(keyList []*KeyInfo, keyName string) (*SpecificKeyInfo, error) {
	for _, keyInfo := range keyList {
		matches, err := keyInfo.Matches(keyName)
		if err != nil {
			return nil, err
		}
		if matches > -1 {
			return &SpecificKeyInfo{
				keyInfo, matches,
			}, nil
		}
	}
	return nil, nil
}

func ReadMainKeys(keySet *KeySet, keyContent string, keyList []*KeyInfo) error {
	prop, err := properties.LoadString(keyContent)
	if err != nil {
		return err
	}
	for k, v := range prop.Map() {
		info, err := typeGetKeyInfo(keyList, k)
		if err != nil {
			return err
		}
		if info == nil {
			fmt.Printf("Could not find specific key: %s\n", k)
		} else {
			key := info.Info.Getter(keySet, info.Index)
			if len(v) != key.Length*2 {
				fmt.Printf("key %s has incorrect size %d must be %d hex digits\n", k, len(v), key.Length*2)
			} else {
				if err = key.StoreFromHex(v); err != nil {
					return err
				}
			}
		}
	}
	return nil
}
